package com.jd.sunny.java;

import org.omg.CORBA.*;

import java.lang.Object;
import java.lang.reflect.*;
import java.util.ArrayList;

/**
 * @Description:reflection use
 * @author:sunlin
 * @since:2012-11-28 16:36
 * @version:1.0.0
 */
public class TestReflection {

    public TestReflection testReflection = new TestReflection();
    private static ArrayList<Object> visited = new ArrayList<Object>();
    public static void main(String[] args ) throws NoSuchFieldException, IllegalAccessException {
//        printClass("com.jd.sunny.java.Employee");

//        getClassField();
        Employee employee = new Employee();
        employee.setName("sunlin");
        employee.setCompany("jd");
        employee.setSalary(1234);
        employee.setSex("man");
        String str =  TestReflection.toString(employee);
        System.out.println(str);
    }

    /**
     * can't use com.jd.sunny.java.TestReflection
     */
    public TestReflection(){

    }

    /**
     * test extends Object getClass() method
     */
    public static void testClass(){
        Employee employee = new Employee();
        Class clas = employee.getClass();
        System.out.println(clas);
    }

    /**
     * print class
     * @param className
     */
    private static void printClass(String className){
        Class cls = null;
        try {
            cls = Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        printClassName(cls);
        printFields(cls);
        printConstructors(cls);
        prinMethods(cls);

        System.out.println("}");
    }

    /**
     * use reflection to print all features of  a class
     */
    private static void printClassName(Class cls){
        String classDes = "";
        //print class name and modifies and super class name
        String modifies =  Modifier.toString(cls.getModifiers());
        classDes =classDes +  modifies + " class " + cls.getName();

        Class superClass =  cls.getSuperclass();
        String superClassName = superClass.getName();
        if(superClassName!=null && superClassName.length()>0){
            classDes = classDes + " extends " + superClassName ;
        }

        Class[] interfaces = cls.getInterfaces();
        if(interfaces!=null&& interfaces.length>0){
            classDes = classDes + " implements ";
            for(int i =0;i<interfaces.length;i++){
                if(i > 0){
                    classDes = classDes + ",";
                }
                classDes = classDes + interfaces[i].getName();
            }
        }
        classDes = classDes + "\n{\n";
        System.out.print(classDes);
    }

    /**
     * print class fields
     */
    private static void printFields(Class cls){
        Field[] fields =  cls.getDeclaredFields();
        for(Field field : fields){
            String fieldModifies =  Modifier.toString(field.getModifiers());
            String fieldName = field.getName();
            System.out.print(fieldModifies + " " + fieldName + ";\n");
        }
        System.out.println();
    }

    /**
     * print class fields
     */
    private static void printConstructors(Class cls){
        Constructor[] constructors =  cls.getDeclaredConstructors();
        for(Constructor constructor : constructors){
            String constructorModifies =  Modifier.toString(constructor.getModifiers());
            String constructorName = constructor.getName();
            System.out.print(constructorModifies + " " + constructorName + "(");

            // print parameter types
            Class[] cl   = constructor.getParameterTypes();
            for(int i =0;i<cl.length;i++){
                if(i > 0){
                    System.out.print(",");
                }
                System.out.print(cl[i].getName());
            }
            System.out.print(");\n");
        }
        System.out.println();
    }

    /**
     * print class fields
     */
    private static void prinMethods(Class cls){
        Method[] methods =  cls.getDeclaredMethods();
        for(Method method : methods){
            String methodModifies =  Modifier.toString(method.getModifiers());
            Class returnType =  method.getReturnType();
            String returnName = returnType.getName();
            String methodName = method.getName();
            System.out.print(methodModifies + " " + returnName + " " + methodName + "(");

            // print parameter types
            Class[] cl   = method.getParameterTypes();
            for(int i =0;i<cl.length;i++){
                if(i > 0){
                    System.out.print(",");
                }
                System.out.print(cl[i].getName());
            }
            System.out.print(");\n");
        }
    }


    /**
     * get field of a class
     */
    private static void getClassField() throws NoSuchFieldException, IllegalAccessException {
        Employee e = new Employee();
        e.setName("sunlin");
        e.setCompany("jd");

        Class cls =  e.getClass();
        Field f2 = cls.getDeclaredField("company");
        //can only get this class field or interfaces field ,can't get father class field
//        Field f1 =  cls.getDeclaredField("name");

        // if the field is modified by private ,must use setAccessible(true); otherwise ,it will throw  java.lang.IllegalAccessException
        f2.setAccessible(true);
        Object object =  f2.get(e);
        System.out.println(object);
    }

    public static String toString(Object object){

        if(object==null){
            return "null";
        }
        if(visited.contains(object)){
            return object.toString() ;//"..."; why?
        }
        visited.add(object);
        Class cls = object.getClass();
        if(cls==String.class){
            return (String)object;
        }
        if(cls.isArray()){
            String r = cls.getComponentType() + "[]{";
            for(int i =0;i<Array.getLength(object);i++){
                if(i>0){
                    r = r + ",";
                }
                Object val = Array.get(object,i);
                if(cls.getComponentType().isPrimitive()){
                    r = r + val;
                }else {
                    r = r + toString(val);
                }
            }
            return r + "}";
        }

        String r =  cls.getName();

        do{
            r = r + "[" ;
            Field[] fields =  cls.getDeclaredFields();
            //set all fields can accessible
            AccessibleObject.setAccessible(fields,true);
            // check the field is static or not
            for(Field field : fields){
                if(! Modifier.isStatic(field.getModifiers())){
                    if(!r.endsWith("[")){
                        r = r + ",";
                    }
                    r = r + field.getName() + "=";
                    try {
                        Object val =  field.get(object);
                        r = r + toString(val);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
            r = r +"]";
            cls =  cls.getSuperclass();
        }while (cls!=null);
        return r;
    }

    //method pointer
    public void methodPointer(){
        Employee employee = new Employee();
        employee.setName("sunlin");
        employee.setCompany("jd");
        employee.setSalary(1234);
        employee.setSex("man");

        
    }














}
